import MainLayout from '@/layouts/main-layout' import { Typography, Box, List, ListItem } from '@mui/material' import { Client } from '@notionhq/client' import Image from 'next/image' import slugify from 'slugify' type PathsProps = { params: { slug: string; } } type ListContent = string[]; type BodyProps = { type: 'paragraph' | 'uList' | 'oList' | 'image'; // Define possible block types content: string | ListContent; // Union type for content } type InnerBlogProps = { title: string; body: BodyProps[]; raw: JSON; } type BlogProps = { blog: InnerBlogProps; } const Blog = ({ blog }: BlogProps) => { return ( <MainLayout> <Box sx={{ px: '2rem', maxWidth: '1400px', mx: 'auto', mt: '1.5rem' }} > <Typography variant='h2'>{blog.title}</Typography> {blog.body.map((item, index) => ( <Box key={index} sx={{ mb: '30px' }}> {item.type === 'paragraph' && ( <Typography>{item.content}</Typography> )} {item.type === 'uList' || item.type === 'oList' && ( <List sx = {{ listStyleType: item.type === 'oList' ? 'number' : 'disc', pl: 2, ml: '2rem', maxWidth: '1000px', '& .MuiListItem-root': { display: 'list-item', }, }} > {(item.content as ListContent).map((listItem, idx) => ( <ListItem key={idx}>{listItem}</ListItem> ))} </List> )} {item.type === 'image' && ( <Image src={item.content as string} width={200} height={200} alt={item.type} /> )} </Box> ))} <pre style={{maxWidth: '100%'}}>{JSON.stringify(blog.raw, null, 2)}</pre> </Box> </MainLayout> ) } export const getStaticPaths = async () => { const notion = new Client({ auth: process.env.NOTION_SECRET, }) const data = await notion.blocks.children.list({ block_id: process.env.BLOG_PAGE_ID, }) const paths: PathsProps[] = [] data.results.forEach(result => { //@ts-ignore if (result.type === 'child_page'){ paths.push({ params: { //@ts-ignore slug: slugify(result.child_page.title).toLowerCase() } }) } }) return { paths, fallback: false, } } export const getStaticProps = async ({ params: { slug }}: PathsProps) => { const notion = new Client({ auth: process.env.NOTION_SECRET, }) const data = await notion.blocks.children.list({ block_id: process.env.BLOG_PAGE_ID, }) const page = data.results.find((result) => { //@ts-ignore if (result.type === 'child_page') { //@ts-ignore const { title } = result.child_page const resultSlug = slugify(title).toLowerCase() return resultSlug === slug } return false; }) if (!page) return { props: { blog: null } } const blocks = await notion.blocks.children.list({ block_id: page.id, }) //@ts-ignore const title = page.child_page.title; const body: BodyProps[] = [] let currentUList: ListContent = []; let currentOList: ListContent = []; const raw = blocks.results; blocks.results.forEach(block => { //@ts-ignore if (block.type === 'paragraph') { //@ts-ignore if (block.paragraph.rich_text.length !== 0) { //@ts-ignore body.push({ type: 'paragraph', content: block.paragraph.rich_text[0].plain_text }); } } //@ts-ignore if (block.type === 'bulleted_list_item') { //@ts-ignore if (block.bulleted_list_item.rich_text.length !== 0) { if (currentUList.length === 0) { //@ts-ignore currentUList.push(block.bulleted_list_item.rich_text[0].plain_text); } else { //@ts-ignore currentUList.push(block.bulleted_list_item.rich_text[0].plain_text); } } } else { if (currentUList.length > 0) { body.push({ type: 'uList', content: currentUList }); currentUList = []; } } //@ts-ignore if (block.type === 'numbered_list_item') { //@ts-ignore if (block.numbered_list_item.rich_text.length !== 0) { if (currentOList.length === 0) { //@ts-ignore currentOList.push(block.numbered_list_item.rich_text[0].plain_text); } else { //@ts-ignore currentOList.push(block.numbered_list_item.rich_text[0].plain_text); } } } else { if (currentOList.length > 0) { body.push({ type: 'oList', content: currentOList }); currentOList = []; } } //@ts-ignore if (block.type === 'image') { //@ts-ignore body.push({ type: 'image', content: block.image.file.url }) } }) if (currentUList.length > 0) { body.push({ type: 'uList', content: currentUList }); } if (currentOList.length > 0) { body.push({ type: 'oList', content: currentOList }); } return { props: { blog: { title, body, raw, }, }, revalidate: 3600, } } export default Blog